using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using XFABManager;

namespace XFGameFramework
{

    public enum UIType
    {
        /// <summary>
        /// 把UI创建在当前场景的Canvas下面，需要对当前模块的Canvas进行赋值
        /// </summary>
        UI = 1,
        /// <summary>
        /// 把UI创建到不被销毁的Canvas下面
        /// </summary>
        DontDestroyUI = 2
    }

    public class PanelManager
    {

        #region 字段

        // 界面与界面之间的层级差量
        internal const int OrderDelta = 10;
        internal const int UI_START_ORDER = 100;
        internal const int DONTDESTROYUI_START_ORDER = 10000;

        /// <summary>
        /// 保存Panel的层级
        /// </summary>
        private static Dictionary<Panel,int> UIOrders = new Dictionary<Panel, int>();
        /// <summary>
        /// 保存DontDestroyPanel的层级
        /// </summary>
        private static Dictionary<Panel,int> DontDestroyUIOrders = new Dictionary<Panel, int>();

        private static List<Panel> TempUIOdersPanels = new List<Panel>();  // 存放临时数据
        private static List<Panel> TempAddOrderPanels = new List<Panel>(); // 存放临时数据

        private static List<Panel> panel_queues = new List<Panel>(); // 保存所有的依次打开的Panel

        private static Panel currentPanel = null; // 当前显示的panel 
         
        private static GameObject _eventSystem;

        private static bool _OPEN_MULTI_PANEL_LISTENNER = false;

        #endregion

        #region 静态属性

        private static GameObject EventSystem
        {
            get {
                if (_eventSystem == null) 
                { 
                    _eventSystem = GameObject.Instantiate(Resources.Load<GameObject>("XFGameFramework/EventSystem"));
                    _eventSystem.name = "EventSystem";
                    GameObject.DontDestroyOnLoad(_eventSystem);
                    _eventSystem.gameObject.SetActive(false); // 默认隐藏 避免场景中有多个EventSystem
                }

                return _eventSystem;
            }
        }

        /// <summary>
        /// Canvas
        /// </summary>
        public static Dictionary<UIType, Canvas> UICanvas { get;private set; } = new Dictionary<UIType, Canvas>();
 
        /// <summary>
        /// 多个界面的重叠监听，默认:true
        /// 当为true时，如果界面的类型为Panel,当该Panel被其他的Panel挡住时,将不会再渲染,以此来节省性能
        /// </summary>
        public static bool MultiPanelListener 
        { 
            get {
                return _OPEN_MULTI_PANEL_LISTENNER;        
            }
            set {
                if (_OPEN_MULTI_PANEL_LISTENNER == value) return;
                _OPEN_MULTI_PANEL_LISTENNER = value;
                if (_OPEN_MULTI_PANEL_LISTENNER)
                {
                    UpdateManager.onLateUpdate += LateUpdate;
                }
                else {
                    UpdateManager.onLateUpdate -= LateUpdate;
                }
            }

        }


        #endregion

        #region 事件

        /// <summary>
        /// 创建Canvas时触发
        /// </summary>
        public static Action<Canvas> onCreateCanvas;

        #endregion

        #region 方法

        static PanelManager()
        {

#if UNITY_EDITOR
            if (!Application.isPlaying) return;
#endif
             
            MultiPanelListener = true;
            EventManager.AddEvent(XFGameFrameworkEvents.ON_REMOVE_VIEW, OnRemoveView);
            SceneManager.sceneLoaded += OnSceneLoaded;
        }

        private static void OnSceneLoaded(Scene arg0, LoadSceneMode arg1)
        {
            // 为了防止新加载的场景中有EventSystem组件，如果有就用场景中的
            EventSystem.SetActive(false);
            if (UnityEngine.EventSystems.EventSystem.current == null)
                EventSystem.SetActive(true);
        }


        // 加载 Panel
        internal static Panel LoadPanel(Module module, string asset_name, UIType type = UIType.UI, Transform parent = null, params object[] param)
        {

            Panel panel = null;

            parent = GetParent(module, parent, type);

            if (parent == null)
            {
                Debug.LogError("parent is null! ");
                return null;
            }

            panel = ViewManager.LoadView(module , asset_name, parent, param) as Panel;

            if (panel == null) return null;

            panel.transform.localPosition = Vector3.zero;

            // 设置层级

            if (panel.IsMyselfAddCanvas)
            {             
                //view.SortingLayerID = SortingLayer.NameToID(type.ToString());
                panel.SortingOrder = GetUIOrder(type);
                panel.UIType = type;
                AddOrder(type, panel, panel.SortingOrder);
                // 添加到panel队列(如果不是自己添加的Canvas，说明当前的UI是在其他的UI里面的，此时不需要考虑被遮挡的情况)
                AddPanelQueue(panel);
            }


            return panel;
        }

        // 异步加载 Panel
        internal static LoadPanelRequest<T> LoadPanelAsync<T>(Module module , string asset_name, UIType type = UIType.UI, Transform parent = null, params object[] param) where T : Panel
        {
            LoadPanelRequest<T> loadPanel = new LoadPanelRequest<T>();
            CoroutineStarter.Start(loadPanel.LoadPanel(module,asset_name, type, parent, param));
            return loadPanel;
        }

        // 获取UI层级
        internal static int GetUIOrderMax(UIType type)
        {

            int layer = 0;
            TempUIOdersPanels.Clear();

            switch (type)
            {
                case UIType.UI:

                    foreach (var item in UIOrders.Keys)
                    {
                        if (item == null)
                        {
                            TempUIOdersPanels.Add(item);
                            continue;
                        }

                        if (UIOrders[item]>layer)
                            layer = UIOrders[item];
                    }

                    foreach (var item in TempUIOdersPanels)
                    {
                        UIOrders.Remove(item);
                    }

                    break;
                case UIType.DontDestroyUI:

                    foreach (var item in DontDestroyUIOrders.Keys)
                    {
                        if (item == null)
                        {
                            TempUIOdersPanels.Add(item);
                            continue;
                        }

                        if (DontDestroyUIOrders[item] > layer)
                            layer = DontDestroyUIOrders[item];
                    }

                    foreach (var item in TempUIOdersPanels)
                    {
                        DontDestroyUIOrders.Remove(item);
                    }

                    break;
            }
             
            return layer;
        }

        internal static int GetUIOrder(UIType type)
        {
            int order = type == UIType.UI ? UI_START_ORDER : DONTDESTROYUI_START_ORDER;
            return GetUIOrderMax(type) + OrderDelta + order;
        }

        // 释放层级
        internal static void ReleaseOrder(Panel panel)
        {
            if (panel == null) return;
            if (UIOrders.ContainsKey(panel))
                UIOrders.Remove(panel);
            if (DontDestroyUIOrders.ContainsKey(panel))
                DontDestroyUIOrders.Remove(panel);
        }

        internal static void AddOrder(UIType type, Panel panel, int order) {
            switch (type)
            {
                case UIType.UI:
                    if(UIOrders.ContainsKey(panel))
                        UIOrders[panel] = order;
                    else
                        UIOrders.Add(panel, order);
                    break;
                case UIType.DontDestroyUI:
                    if (DontDestroyUIOrders.ContainsKey(panel))
                        DontDestroyUIOrders[panel] = order;
                    else
                        DontDestroyUIOrders.Add(panel, order);
                    break; 
            }

            // 更新所有在最前面的界面的层级
            UpdateAlwaysInFront(); 
        }

        internal static void UpdateAlwaysInFront()
        {
            // 找到所有始终显示在最上层的界面 TODO
            TempAddOrderPanels.Clear();
            foreach (var item in UIOrders.Keys)
            {
                if (item != null && item.AlwaysInFront)
                    TempAddOrderPanels.Add(item);
            }

            foreach (var item in TempAddOrderPanels)
            {
                item.SortingOrder = GetUIOrder(UIType.UI);
                item.transform.SetAsLastSibling(); // 节点设置到最后一个
            }

            TempAddOrderPanels.Clear();

            foreach (var item in DontDestroyUIOrders.Keys)
            {
                if (item != null && item.AlwaysInFront)
                    TempAddOrderPanels.Add(item);
            }

            foreach (var item in TempAddOrderPanels)
            {
                item.SortingOrder = GetUIOrder(UIType.DontDestroyUI);
                item.transform.SetAsLastSibling(); // 节点设置到最后一个
            }

        }

        internal static void LateUpdate() {
            UpdatePanelQueue();
        }

        internal static void OnRemoveView(object[] param) 
        {
            if (param == null || param.Length == 0) return;
            Panel panel = param[0] as Panel;
            if (panel == null) return;
            RemovePanelQueue(panel);
            ReleaseOrder(panel);
        }

        internal static Transform GetParent(Module module,Transform parent,UIType type) 
        {
            // 判断是否需要开启EventSystem 
            if (UnityEngine.EventSystems.EventSystem.current == null)
                EventSystem.SetActive(true);
            else 
            {
                if (UnityEngine.EventSystems.EventSystem.current.gameObject != EventSystem)
                    EventSystem.SetActive(false);
            }
            

            if (parent != null) return parent;

            try
            {
                if (UICanvas.ContainsKey(type) && UICanvas[type] != null)
                    return UICanvas[type].transform;
            }
            catch (System.Exception)
            { 
            }


            UICanvas.Remove(type);

            GameObject canvasObj = GameObject.Instantiate(Resources.Load<GameObject>("XFGameFramework/Canvas"));
            Canvas canvas = canvasObj.GetComponent<Canvas>();
 
            canvas.sortingOrder = type == UIType.UI ? UI_START_ORDER : DONTDESTROYUI_START_ORDER;

            if (type == UIType.DontDestroyUI)
                GameObject.DontDestroyOnLoad(canvasObj);

            UICanvas.Add(type, canvas);
            // 触发事件
            onCreateCanvas?.Invoke(canvas);
            return canvas.transform;
        }

#endregion

        #region 自动管理多个Panel重叠问题

        internal static void AddPanelQueue(Panel panel)
        {
            // 判断是否开启该功能
            if (!MultiPanelListener) return;
            if (panel == null || panel.PanelType == PanelType.Window) return;

            // 检测当前的panel 是否已经在队列中 如果已经存在 需要移除
            if (panel_queues.Contains(panel)) panel_queues.Remove(panel);
            // 加入队列
            panel_queues.Add(panel);

            if (panel_queues.Count > 20) Debug.LogWarning("PanelManager.panel_queues队列数量过多,请检查是否存在异常!");

            currentPanel = panel;

            // 把前面的Panel位置进行修改
            for (int i = 0; i < panel_queues.Count - 1; i++)
            {
                if (panel_queues[i].Canvas.enabled)
                {
                    panel_queues[i].Canvas.enabled = false;
                    panel_queues[i].Invisible();
                }
            }

        }

        internal static void RemovePanelQueue(Panel panel)
        {
            // 判断是否开启该功能
            if (!MultiPanelListener) return;
            if (panel == null) return;
            panel_queues.Remove(panel);

            if (panel == currentPanel) ReturnToPreviousPanel();
        }


        // 更新Panel队列
        internal static void UpdatePanelQueue()
        {
            // 判断是否开启该功能
            if (!MultiPanelListener) return;
            if (currentPanel == null) return;

            // 监听当前的页面是否被关掉 或者 销毁
            if (currentPanel.gameObject == null || currentPanel.gameObject.IsDestroy() || !currentPanel.gameObject.activeSelf)
            {
                while (panel_queues.Count > 0)
                {
                    Panel last = panel_queues[panel_queues.Count - 1];
                    panel_queues.RemoveAt(panel_queues.Count - 1);
                    if (last == currentPanel) break;
                }

                // 把最后一个设置成当前的
                ReturnToPreviousPanel();
            }
        }

        // 返回到上一个界面
        internal static void ReturnToPreviousPanel()
        {
            if (panel_queues.Count == 0) return;
            Panel last = panel_queues[panel_queues.Count - 1];
            if (last == null) return;
            if (last.Canvas.enabled == false)
            {
                last.Canvas.enabled = true;
                last.Visible();
            }
        }

        #endregion


    }
}

